Skip to content

Conversation

@Shnatsel
Copy link
Contributor

@Shnatsel Shnatsel commented Jan 22, 2026

Using vectorize() as opposed to directly calling functions annotated #[inline(always)] is meant to introduce an inlining barrier and make the compiler make inlining decisions. Therefore putting #[inline] on it is rather pointless: if I wanted aggressive inlining, I wouldn't be calling vectorize() in the first place.

#[inline] also enables cross-crate inlining, but since vectorize() is a generic function it will be instantiated in the caller crate, so this is not a concern.

More info about inlining: https://matklad.github.io/2021/07/09/inline-in-rust.html

Motivation

I'm seeing a large performance regression from switching from wide to fearless_simd in QuState/PhastFT#58 due to overly aggressive inlining. This alone doesn't fix it, but seems like a sensible first step. It's not clear if over-zealous inlining was a cause of the regression, there are other factors. I'll re-measure once #185 lands.

@LaurenzV
Copy link
Collaborator

LaurenzV commented Jan 23, 2026

I'm not sure if it's intended like this, based on the description:

- All SIMD functions need `#[inline(always)]`.
- Use [`dispatch!`] when calling SIMD code from non-SIMD code.
- Use [`vectorize()`](Simd::vectorize) when calling SIMD from SIMD if you don't want to force inlining.

@DJMcNab probably knows more.

Copy link
Member

@DJMcNab DJMcNab left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I agree that the inline attributes are currently overzealous. I believe however that this PR goes too far the other way.
I think that it's also possible that the inner functions should be more properly marked as inline(never) (or even that we should provide two versions of vectorize, one which is unhinted and one which inline(never))

I want to see what Valerie thinks here.

fn level(self) -> Level {
Level::Avx2(self)
}
#[inline]
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This function should still be #[inline] (indeed, I believe that it possibly should be inline(always)). This is because we don't want to force LLVM to change its calling convention to call this function, we just want to break unneeded inlining.

fn level(self) -> Level {
Level::Neon(self)
}
#[inline]
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As here

Level::baseline()
}
}
#[inline]
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

And here

#[cfg(not(feature = "force_support_fallback"))]
Level::baseline()
}
#[inline]
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

(But not here)

fn level(self) -> Level {
Level::WasmSimd128(self)
}
#[inline]
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

(Nor here)

@Shnatsel
Copy link
Contributor Author

Shnatsel commented Jan 23, 2026

Thanks! That makes sense, I'll try to update this PR with those changes (no #[inline] on inner functions, #[inline] or #[inline(always)] on outer ones).

I don't think a second vectorize() with #[inline(never)] is worth the confusion of having two similar functions since it's not terribly hard to DIY if you need it: QuState/PhastFT@31954e7

@Shnatsel
Copy link
Contributor Author

I've updated the PR to only remove #[inline] from the inner functions annotated with #[target_feature(...)]

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants